package LB1;

import static java.lang.Math.*;

/**
 * Created with IntelliJ IDEA.
 * User: Борис
 * Date: 22.09.13
 * Time: 20:03
 * To change this template use File | Settings | File Templates.
 */
public class Work {
    //private double h0, h1, h2;
    private double[][] gridFunction;
    private final int n=6;
    public Work(double[][] gridFunction){
        this.gridFunction = gridFunction;
    }
    public void mainFunction(){
        //double h0, h1, h2; // коэффициенты многочлена: h0 - свободный член, h1 - средний коэффициент, h2 - старший коэффициент
        int i,j;
        System.out.println("Сеточная функция:");
        for(j = 0; j<n; j++){
            if(j == 0) System.out.println("x\ty\t");
            for(i = 0; i<2; i++){
                System.out.print(gridFunction[i][j]+"\t");
            }
            System.out.println();
        }
        double k1,k2;   // коеффициенты системы
        k1=k2=0;
        double s1,s2;    // свободные члены
        s1=s2=0;
        // вычисление коэффициентов системы а)
        for(i=0;i<n;i++){
            k1+=gridFunction[0][i];
            k2+=pow(gridFunction[0][i],2);
            s1+=gridFunction[1][i];
            s2+=gridFunction[0][i]*gridFunction[1][i];
        }
        double[][] matrixOfSystem2x2 = {
                {n, k1},
                {k1,k2}
        };
        double[] line = {s1,s2};
        double[] answer = answerA(matrixOfSystem2x2,line);
        double h0 = answer[0];
        double h1 = answer[1];
        System.out.println("\nМногочлен а): "+h1+"*X + "+h0);
        System.out.println("\nЗначения многочлена a) в узлах сетки");
        double[][] valuesPolynomial = polynomial(h1,h0);
        for(j = 0; j<n; j++){
            if(j == 0) System.out.println("x\tP(x)\t");
            for(i = 0; i<2; i++){
                System.out.print(valuesPolynomial[i][j]+"\t");
            }
            System.out.println();
        }
        System.out.println("\nСреднеквадратичное отклонение: "+standardDeviation(h1,h0));
        //System.out.println("\nСреднеквадратичное отклонение: "+standardDeviation(1,2));
        double A,B,C,D,S,L,M;
        A=B=C=D=S=L=M=0;
        // вычисление коэффициентов системы б)
        for(i = 0; i<n; i++){
            A+=gridFunction[0][i];
            B+=pow(gridFunction[0][i],2);
            C+=pow(gridFunction[0][i],3);
            D+=pow(gridFunction[0][i],4);
            S+=gridFunction[1][i];
            L+=gridFunction[0][i]*gridFunction[1][i];
            M+=pow(gridFunction[0][i],2)*gridFunction[1][i];
        }
        double[][] matrixOfSystem3x3 = {
                {n, A, B},
                {A, B, C},
                {B, C, D}
        };
        double[] lineThree = {S, L, M};
        answer = answerB(matrixOfSystem3x3,lineThree);
        h0 = answer[0];
        h1 = answer[1];
        double h2 = answer[2];
        System.out.println("\nМногочлен б): "+h2+"*X^2 + "+h1+"*X + "+h0);
        System.out.println("\nЗначения многочлена б) в узлах сетки");
        valuesPolynomial = polynomial(h2,h1,h0);
        for(j = 0; j<n; j++){
            if(j == 0) System.out.println("x\tP(x)\t");
            for(i = 0; i<2; i++){
                System.out.print(valuesPolynomial[i][j]+"\t");
            }
            System.out.println();
        }
        System.out.println("\nСреднеквадратичное отклонение: "+standardDeviation(h2,h1,h0));
    }
    /*
    вычисляет определитель матрицы размера 2х2
    matrix - матрица, определитель которой надо вычислить
      */
    public double determinantSizeTwo(double[][] matrix){
        return matrix[0][0]*matrix[1][1]-matrix[1][0]*matrix[0][1];
    }
    /*
    решает систему уравнений а);
    matrix - матрица системы
    line - столбец свободных членов
      */
    public double[] answerA(double[][] matrix, double[] line){
        double[][] matrix2 =  new double[2][2]; // сохраняю matrix в matrix2
        for(int i = 0; i<2; i++)
            for(int j = 0; j<2; j++){
                matrix2[i][j]=matrix[i][j];
            }
        matrix2[1][1] = matrix[1][1];
        double det = determinantSizeTwo(matrix); // det - определитель матриы системы
        matrix[0][0] = line[0];
        matrix[1][0] = line[1];
        double det1 = determinantSizeTwo(matrix);
        matrix2[0][1] = line[0];
        matrix2[1][1] = line[1];
        double det2 = determinantSizeTwo(matrix2);
        double[] decision = new double[2];
        decision[0] = det1/det;   //decision[0] - h0 - свободный член
        decision[1] = det2/det;   //decision[1] - h1 - старший коэффициент
        return decision;
    }
    /*
    решает систему уравнений б)
    matrix - матрица системы
    line - столбец свободных членов
      */
    public double[] answerB( double[][] matrix,double line[]){
        double[][] matrix2 =  new double[3][3];
        int i;
        for(i = 0; i<3; i++) // сохраняю matrix в matrix2
            for(int j = 0; j<3; j++){
                matrix2[i][j]=matrix[i][j];
            }
        double det = determinantSizeThree(matrix);  // определитель матрицы системы
        for(i = 0; i<3; i++) // первый столбец матрицы системы
            matrix[i][0]=line[i];
        double det1 = determinantSizeThree(matrix);
        matrix=matrix2;
        double[][] matrix3 = new double[3][3];
        for(i = 0; i<3; i++) // сохраняю matrix2 в matrix3
            for(int j = 0; j<3; j++){
                matrix3[i][j]=matrix2[i][j];
            }
        for(i = 0; i<3; i++)
            matrix[i][1] = line[i];
        double det2 = determinantSizeThree(matrix);
        matrix = matrix3;
        for(i = 0; i<3; i++)
            matrix[i][2] = line[i];
        double det3 = determinantSizeThree(matrix);
        double[] answer = {det1/det, det2/det, det3/det} ;
        return answer;
    }
    // метод вычисляет определитель матрицы 3х3
    public double determinantSizeThree(double[][] matrix){
        double[][] matrixTwoByTwoLeft, matrixTwoByTwoCenter, matrixTwoByTwoRight;
        matrixTwoByTwoLeft = getTwoByTwoMatrixLeft(matrix);
        matrixTwoByTwoCenter = getTwoByTwoMatrixCenter(matrix);
        matrixTwoByTwoRight = getTwoByTwoMatrixRight(matrix);
        return matrix[0][0]*determinantSizeTwo(matrixTwoByTwoLeft)-matrix[0][1]*determinantSizeTwo(matrixTwoByTwoCenter)+matrix[0][2]*determinantSizeTwo(matrixTwoByTwoRight);
    }
    /*
     метод возвращает матрицу 2x2, когда вычеркнут левый столбец
     matrix[] - матрица 3х3 \
     */
    public double[][] getTwoByTwoMatrixLeft(double[][] matrix){
        double[][] matrixTwoByTwo = new double[2][2];
        matrixTwoByTwo[0][0] = matrix[1][1];
        matrixTwoByTwo[0][1] = matrix[1][2];
        matrixTwoByTwo[1][0] = matrix[2][1];
        matrixTwoByTwo[1][1] = matrix[2][2];
        return matrixTwoByTwo;
    }
    /*
     метод возвращает матрицу 2x2, когда вычеркнут центральный столбец
     matrix[] - матрица 3х3
     */
    public double[][] getTwoByTwoMatrixCenter(double[][] matrix){
        double[][] matrixTwoByTwo = new double[2][2];
        matrixTwoByTwo[0][0] = matrix[1][0];
        matrixTwoByTwo[0][1] = matrix[1][2];
        matrixTwoByTwo[1][0] = matrix[2][0];
        matrixTwoByTwo[1][1] = matrix[2][2];
        return matrixTwoByTwo;
    }
    /*
     метод возвращает матрицу 2x2, когда вычеркнут правый столбец
     matrix[] - матрица 3х3
     */
    public double[][] getTwoByTwoMatrixRight(double[][] matrix){
        double[][] matrixTwoByTwo = new double[2][2];
        matrixTwoByTwo[0][0] = matrix[1][0];
        matrixTwoByTwo[0][1] = matrix[1][1];
        matrixTwoByTwo[1][0] = matrix[2][0];
        matrixTwoByTwo[1][1] = matrix[2][1];
        return matrixTwoByTwo;
    }
    // вычисляет значение полинома степени 2 в узлах сетки
    public double[][] polynomial(double k1, double k0){
        double[][] valuesPolynomial = new double[2][n];
        int i;
        for(i = 0; i<n; i++){
            valuesPolynomial[0][i] = gridFunction[0][i];
            valuesPolynomial[1][i] = k1*valuesPolynomial[0][i]+k0;
        }
        return valuesPolynomial;
    }
    /*
    возвращает массив из двух строк и n столбцов
    первая строка массива - это узлы сетки
    вторая строка массива - это значения многочлена в узлах сетки
    k2 - старший коэффициент, k1 - средний коэффициент, k0 - свободный член
      */
    public double[][] polynomial(double k2, double k1, double k0){
        double[][] valuesPolynomial = new double[2][n];
        for(int i = 0; i<n; i++){
            valuesPolynomial[0][i] = gridFunction[0][i];
            valuesPolynomial[1][i] = k2*pow(valuesPolynomial[0][i],2)+k1*valuesPolynomial[0][i]+k0;
        }
        return valuesPolynomial;
    }
    /* метод вычисляет среднеквадратичное отклонение для полинома степени 2
       k1 - старший коэффициент, k0 - свободный член
       */
    public double standardDeviation(double k1, double k0){
        double sum = 0;
        double[][] valuesPolynomial = polynomial(k1,k0);
        for(int i = 0; i<n; i++){
            sum = sum + pow(valuesPolynomial[1][i] - gridFunction[1][i],2);
        }
        return sqrt((1.0/n)*sum);
    }
    /* метод вычисляет среднеквадратичное отклонение для полинома степени 2
       k2 - старший коэффициент, k1 - средний коэффициент, k0 - свободный член
       */
    public double standardDeviation(double k2, double k1, double k0){
        double sum = 0;
        double[][] valuesPolynomial = polynomial(k2,k1,k0);
        for(int i = 0; i<n; i++){
            sum = sum + pow(valuesPolynomial[1][i] - gridFunction[1][i],2);
        }
        return sqrt(sum/n);
    }
}
